﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenSSL.X509;
using OpenSSL.Core;
using Sicurezza.Client.Manager;
using Sicurezza.Entita;
using System.IO;
using OpenSSL.Crypto;
using Sicurezza.Manager;

namespace Sicurezza.Client.Controlli
{
    public partial class SendFileControl : UserControl
    {
        private X509Certificate cert = null;
        private string password = null;
        private Dictionary<int, X509Certificate> recipients = new Dictionary<int, X509Certificate>();
        private List<string> files = new List<string>();
        private OpenForm RecipentsForm = new OpenForm(OpenForm.Mode.Recipient);
        private string SmtpUsername = "";
        private string SmtpPassword = "";
        private bool canSign = false;
        private bool canEncipher = false;
        public event EventHandler RequestingRecipients;
        public event EventHandler RequestingRecipientsEnd;
        public event EventHandler SendingMail;
        public event EventHandler SendingMailEnd;

        public SendFileControl()
        {
            InitializeComponent();
        }

        private void chooseSenderButton_Click(object sender, EventArgs e)
        {
            HideButtons();
            OpenForm of = new OpenForm(OpenForm.Mode.Certificate);
            if (of.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(of.SelectedId))
                return;

            PasswordForm pf = new PasswordForm();
            if (pf.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(pf.Password))
                return;

            password = pf.Password;
            cert = new X509Certificate(new BIO(FileManager.LoadCertificate(of.SelectedId)));

            dnText.Text = X509Manager.GetDN(cert);
            emailText.Text = X509Manager.GetEmail(cert);
            signatureCheck.Checked = X509Manager.IsSignAllowed(cert);
            encipherCheck.Checked = X509Manager.IsEncipherAllowed(cert);

            ShowButtons(signatureCheck.Checked, encipherCheck.Checked);
        }

        private void HideButtons()
        {
            signSendButton.Enabled = false;
            encipherSendButton.Enabled = false;
            signEncipherSendButton.Enabled = false;
            addRecipientButton.Enabled = false;
            addFileButton.Enabled = false;
        }

        private void ShowButtons(bool signature, bool encipher)
        {

            canEncipher = encipher;
            canSign = signature;

            ShowButtons();
            
        }

        private void ShowButtons()
        {
            addFileButton.Enabled = true;
            addRecipientButton.Enabled = true;

            if (canSign && canEncipher)
            {
                signSendButton.Enabled = true;
                encipherSendButton.Enabled = true;
                signEncipherSendButton.Enabled = true;
                return;
            }
            if (canSign)
                signSendButton.Enabled = true;

            if (canEncipher)
                encipherSendButton.Enabled = true;
        }

        public void Reset()
        {
            cert = null;
            dnText.Text = "";
            emailText.Text = "";
            SmtpUsername = "";
            SmtpPassword = "";
            signatureCheck.Checked = false;
            encipherCheck.Checked = false;
            recipientList.Items.Clear();
            fileList.Items.Clear();
            files.Clear();
            recipients.Clear();
            addRecipientButton.Enabled = false;
            addFileButton.Enabled = false;
            RecipentsForm.DataSource = null;
            HideButtons();
        }

        private void addRecipientButton_Click(object sender, EventArgs e)
        {
            if (RecipentsForm.DataSource == null)
            {
                RequestingRecipients(null, null);
                RecipentsForm.DataSource = MailManager.GetRecipients(cert, password, signatureCheck.Checked, encipherCheck.Checked);
                RequestingRecipientsEnd(null, null);
            }
            if (RecipentsForm.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(RecipentsForm.SelectedId))
                return;
            
            recipientList.Items.Add(RecipentsForm.SelectedDN);

            int recipientSerial = Convert.ToInt32(RecipentsForm.SelectedId);
            X509Certificate recipientCertificate = X509Manager.Get(recipientSerial);
            recipients.Add(recipientSerial, recipientCertificate);

            bool signature = X509Manager.IsSignAllowed(recipientCertificate);
            bool encipher = X509Manager.IsEncipherAllowed(recipientCertificate);

            ShowButtons(signature, encipher);

        }

        private void addFileButton_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(openFileDialog1.FileName))
                return;
            FileInfo fi = new FileInfo(openFileDialog1.FileName);
            files.Add(openFileDialog1.FileName);
            fileList.Items.Add(fi.Name );
        }

        private void encipherSendButton_Click(object sender, EventArgs e)
        {
            PrepareSend();

            ChooseEncipherAlgorithm cea = new ChooseEncipherAlgorithm();
            if (cea.ShowDialog() != DialogResult.OK || cea.SymmetricAlgorithm == null)
            {
                ShowButtons();
                return;
            }

            int[] keys = recipients.Keys.ToArray();
            for (int i = 0; i < keys.Length; i++)
            {
                int serial = keys[i];
                MailMessage mm = Encipher(recipients[serial], cea.SymmetricAlgorithm.TypeName);
                SignedMessage sm = new SignedMessage();
                sm.Message = XmlManager.Serialize(mm);
                if (!SendMail(sm, X509Manager.GetEmail(cert), X509Manager.GetEmail(recipients[serial])))
                    return;
            }

            Reset();
            
        }

        

        private bool SendMail(SignedMessage sm, string from, string to)
        {
            SendingMail(to, null);
            try
            {
                MailManager.Send(sm, from, to, SmtpUsername, SmtpPassword);
            }
            catch (ManagerException ex)
            {
                MsgBox.Error(ex.Message);
                return false;
            }
            finally
            {
                SendingMailEnd(null, null);
                ShowButtons();
            }

            return true;
        }

        private MailMessage Encipher(X509Certificate recipientCertificate, string cipher)
        {
            
            MailMessage mm = new MailMessage();
            mm.SenderSerial = cert.SerialNumber;
            mm.RecipientSerial = recipientCertificate.SerialNumber;
            mm.Cipher = cipher;
            mm.EncipheredKey = KeyManager.Generate();
            mm.IV = KeyManager.GenerateIV();
            mm.Files = SSLManager.Encipher(files, mm);
            mm.EncipheredKey = SSLManager.Encipher(mm.EncipheredKey, recipientCertificate.PublicKey);

            return mm;
        }

        private void PrepareSend()
        { 
            HideButtons();

            PasswordForm pf = new PasswordForm();
            pf.DialogText = "Insert Smtp server credentials";
            pf.CredentialsMode = true;
            if (pf.ShowDialog() != DialogResult.OK ||
                string.IsNullOrEmpty(pf.Password) ||
                string.IsNullOrEmpty(pf.Username))
            {
                ShowButtons();
                return;
            }

            SmtpUsername = pf.Username;
            SmtpPassword = pf.Password;
        }

        private void signSendButton_Click(object sender, EventArgs e)
        {
            PrepareSend();

            X509Certificate recipientCertificate = null;
            int[] keys = recipients.Keys.ToArray();
            for (int i = 0; i < keys.Length; i++)
            {
                int serial = keys[i];
                recipientCertificate = recipients[serial];
                MailMessage mm = new MailMessage();
                mm.RecipientSerial = serial;
                mm.SenderSerial = cert.SerialNumber;
                mm.Files = FileManager.GetFiles(files);
                SignedMessage sm = new SignedMessage();
                sm.Message = XmlManager.Serialize(mm);
                sm.Signature = SSLManager.Sign(sm.Message, cert, password);

                if (!SendMail(sm, X509Manager.GetEmail(cert), X509Manager.GetEmail(recipientCertificate)))
                    return;
            }

            Reset();
        }

        private void signEncipherSendButton_Click(object sender, EventArgs e)
        {
        PrepareSend();

            ChooseEncipherAlgorithm cea = new ChooseEncipherAlgorithm();
            if (cea.ShowDialog() != DialogResult.OK || cea.SymmetricAlgorithm == null)
            {
                ShowButtons();
                return;
            }
            X509Certificate recipientCertificate = null;
            int[] keys = recipients.Keys.ToArray();
            for (int i = 0; i < keys.Length; i++)
            {
                int serial = keys[i];
                recipientCertificate = recipients[serial];
                MailMessage mm = Encipher(recipientCertificate, cea.SymmetricAlgorithm.TypeName);
                SignedMessage sm = new SignedMessage();
                sm.Message = XmlManager.Serialize(mm);
                sm.Signature = SSLManager.Sign(sm.Message, cert, password);

                if (!SendMail(sm, X509Manager.GetEmail(cert), X509Manager.GetEmail(recipientCertificate)))
                    return;
            }

            Reset();
        }
    }
}
